/*
 * Copyright (c) 2021 Huawei Device Co.,  Ltd.
 * Licensed under the Apache License,  Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,  software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,  either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "iccreader_observer.h"
#include <string.h>
#include <uv.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <iccreader_def.h>
#include "iccreader_hilog.h"
#include "iccreader_utils.h"
#include "event_runner.h"
#include "event_handler.h"
#include "event_queue.h"

namespace SwanLink {
namespace Finance {
using namespace OHOS;

SearchResultObserver::SearchResultObserver() :
    searcher_(nullptr),
    handler_(std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner())) {
}

SearchResultObserver::~SearchResultObserver() {
    if (searcher_) {
        delete searcher_;
    }
}

void SearchResultObserver::PushObserver(const napi_env &env, const napi_value &listener) {
    std::lock_guard<std::mutex>  lock(mutex_);
    if (searcher_) {
        delete searcher_;
    }
    searcher_ = new NapiSearchResult();
    searcher_->env = env;
    napi_value func_succ, func_fail;
    DEBUG_NAPI_CALL_NO_RET(env, napi_get_named_property(env, listener, "OnResult", &func_succ));
    DEBUG_NAPI_CALL_NO_RET(env, napi_get_named_property(env, listener, "OnError", &func_fail));
    napi_create_reference(env, func_succ, 1, &searcher_->func_succ_ref);
    napi_create_reference(env, func_fail, 1, &searcher_->func_fail_ref);

    ICCREADER_HILOGD(ICCREADER_JS_NAPI, "observer has been registered");
}

void SearchResultObserver::PopObserver() {
    std::lock_guard<std::mutex>  lock(mutex_);
    if (searcher_) {
        delete searcher_;
    }
    searcher_ = nullptr;
}

void SearchResultObserver::OnResult(int status, const ResultData &data) {
    ICCREADER_HILOGD(ICCREADER_JS_NAPI, "status = %{public}d", status);

    std::lock_guard<std::mutex>  lock(mutex_);
    if (searcher_ == nullptr) {
        ICCREADER_HILOGE(ICCREADER_JS_NAPI, "observer has been removed");
        return;
    }
    ICCREADER_HILOGE(ICCREADER_JS_NAPI, "observer call success");
    NapiSearchResult *searcher = searcher_;
    auto task = [searcher, status, data]() {
        searcher->OnResult(status, data);
    };

    handler_->PostTask(task, "OnResult");
}
void SearchResultObserver::OnError(int status, const std::string& err) {
    ICCREADER_HILOGD(ICCREADER_JS_NAPI, "status = %{public}d, err = %{public}s", status, err.c_str());
    std::lock_guard<std::mutex>  lock(mutex_);
    if (searcher_ == nullptr) {
        ICCREADER_HILOGE(ICCREADER_JS_NAPI, "observer has been removed");
        return;
    }
    NapiSearchResult *searcher = searcher_;
    auto task = [searcher, status, err]() {
        searcher->OnError(status, err);
    };
    handler_->PostTask(task, "OnError");
}

NapiSearchResult::NapiSearchResult() :
    env(nullptr),
    func_succ_ref(nullptr),
    func_fail_ref(nullptr) {
}

NapiSearchResult::~NapiSearchResult() {
    if (func_succ_ref) {
        napi_delete_reference(env, func_succ_ref);
    }

    if (func_fail_ref) {
        napi_delete_reference(env, func_fail_ref);
    }
}

void NapiSearchResult::OnResult(int status, const ResultData &result) {
    napi_value undefined = nullptr;
    napi_value callResult = nullptr;
    napi_value args[2] = {nullptr};
    napi_value func_succ;

    ICCREADER_HILOGE(ICCREADER_JS_NAPI, "observer func_succ = %{public}p", func_succ_ref);

    DEBUG_NAPI_CALL_NO_RET(env, napi_create_int32(env, status, &args[0]));
    args[1] = ResultDataToNapi(env, result);

    DEBUG_NAPI_CALL_NO_RET(env, napi_get_undefined(env, &undefined));
    DEBUG_NAPI_CALL_NO_RET(env, napi_get_reference_value(env, func_succ_ref, &func_succ));

    DEBUG_NAPI_CALL_NO_RET(env, napi_call_function(env, nullptr, func_succ, 2, args, &callResult));
}

void NapiSearchResult::OnError(int status, const std::string& err) {
    napi_value undefined = nullptr;
    napi_value callResult = nullptr;
    napi_value args[2] = {nullptr};
    napi_value func_fail;

    napi_create_int32(env, status, &args[0]);
    napi_create_string_utf8(env, err.c_str(), NAPI_AUTO_LENGTH, &args[1]);

    DEBUG_NAPI_CALL_NO_RET(env, napi_get_undefined(env, &undefined));
    DEBUG_NAPI_CALL_NO_RET(env, napi_get_reference_value(env, func_fail_ref, &func_fail));
    DEBUG_NAPI_CALL_NO_RET(env, napi_call_function(env, nullptr, func_fail, 2, args, &callResult));
}
}  // namespace Finance
}  // namespace SwanLink